import type { WordUpdateAction } from '../InputHandler'
import InputHandler from '../InputHandler'
import Letter from './Letter'
import Notation from './Notation'
import { TipAlert } from './TipAlert'
import style from './index.module.css'
import { initialWordState } from './type'
import type { WordState } from './type'
import Tooltip from '@/components/Tooltip'
import type { WordPronunciationIconRef } from '@/components/WordPronunciationIcon'
import { WordPronunciationIcon } from '@/components/WordPronunciationIcon'
import { EXPLICIT_SPACE } from '@/constants'
import useKeySounds from '@/hooks/useKeySounds'
import { TypingContext, TypingStateActionType } from '@/pages/Typing/store'
import {
  currentChapterAtom,
  currentDictInfoAtom,
  isIgnoreCaseAtom,
  isShowAnswerOnHoverAtom,
  isTextSelectableAtom,
  pronunciationIsOpenAtom,
  wordDictationConfigAtom,
} from '@/store'
import type { Word } from '@/typings'
//
import { CTRL, getUtcStringForMixpanel } from '@/utils'
import { useSaveWordRecord } from '@/utils/db'
import { useAtomValue } from 'jotai'
import { useCallback, useContext, useEffect, useRef, useState } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { useImmer } from 'use-immer'

const vowelLetters = ['A', 'E', 'I', 'O', 'U']

export default function WordComponent({ word, onFinish }: { word: Word; onFinish: () => void }) {
  // eslint-disable-next-line  @typescript-eslint/no-non-null-assertion
  const { state, dispatch } = useContext(TypingContext)! // 获取打字状态和分发函数
  const [wordState, setWordState] = useImmer<WordState>(structuredClone(initialWordState)) // 单词状态
  console.log('wordState', state)
  const wordDictationConfig = useAtomValue(wordDictationConfigAtom) // 监听是否开启单词听写功能
  const isTextSelectable = useAtomValue(isTextSelectableAtom) // 监听是否允许选中文字
  const isIgnoreCase = useAtomValue(isIgnoreCaseAtom) // 监听是否忽略大小写
  const isShowAnswerOnHover = useAtomValue(isShowAnswerOnHoverAtom) // 监听是否开启悬停显示答案功能
  const saveWordRecord = useSaveWordRecord() // 保存单词记录的函数
  // const wordLogUploader = useMixPanelWordLogUploader(state)
  const [playKeySound, playBeepSound, playHintSound] = useKeySounds() // 获取播放按键音、错误音和提示音的函数
  const pronunciationIsOpen = useAtomValue(pronunciationIsOpenAtom) // 监听是否开启发音功能
  const [isHoveringWord, setIsHoveringWord] = useState(false) // 是否正在悬停在单词上
  const currentLanguage = useAtomValue(currentDictInfoAtom).language // 当前语言
  const currentLanguageCategory = useAtomValue(currentDictInfoAtom).languageCategory //currentLanguageCategory 当前语言类别
  const currentChapter = useAtomValue(currentChapterAtom) // 当前章节

  const [showTipAlert, setShowTipAlert] = useState(false) // 是否显示提示警告
  const wordPronunciationIconRef = useRef<WordPronunciationIconRef>(null) // ref 用于控制发音图标组件

  useEffect(() => {
    // run only when word changes//
    let headword = '' // 处理单词名称，替换空格和省略号
    try {
      headword = word.name.replace(new RegExp(' ', 'g'), EXPLICIT_SPACE)
      headword = headword.replace(new RegExp('…', 'g'), '..')
    } catch (e) {
      console.error('word.name is not a string', word)
      headword = ''
    } // 初始化单词状态

    const newWordState = structuredClone(initialWordState) // 克隆初始单词状态
    newWordState.displayWord = headword // 设置显示的单词
    newWordState.letterStates = new Array(headword.length).fill('normal') // 初始化字母状态数组
    newWordState.startTime = getUtcStringForMixpanel() // 记录开始时间
    newWordState.randomLetterVisible = headword.split('').map(() => Math.random() > 0.4) // 随机字母可见性数组
    setWordState(newWordState) //  设置单词状态
  }, [word, setWordState]) // 初始化单词状态，当单词变化时触发

  const updateInput = useCallback(
    (updateAction: WordUpdateAction) => {
      switch (updateAction.type) {
        case 'add':
          if (wordState.hasWrong) return // 如果单词状态为错误，则不处理输入

          if (updateAction.value === ' ') {
            updateAction.event.preventDefault()
            setWordState((state) => {
              state.inputWord = state.inputWord + EXPLICIT_SPACE
            }) // 将空格替换为显式空格
          } else {
            setWordState((state) => {
              state.inputWord = state.inputWord + updateAction.value // 添加输入的字符到输入单词
            }) // 添加输入的字符到输入单词
          } // 处理添加字符的输入更新
          break

        default:
          console.warn('unknown update type', updateAction)
      } // 处理输入更新的回调函数
    },
    [wordState.hasWrong, setWordState],
  ) // 处理输入更新的回调函数

  const handleHoverWord = useCallback((checked: boolean) => {
    setIsHoveringWord(checked)
  }, []) // 处理悬停单词的回调函数

  useHotkeys(
    'tab',
    () => {
      handleHoverWord(true)
    },
    { enableOnFormTags: true, preventDefault: true },
    [],
  ) // 使用快捷键 tab 显示完整单词

  useHotkeys(
    'tab',
    () => {
      handleHoverWord(false)
    },
    { enableOnFormTags: true, keyup: true, preventDefault: true },
    [],
  ) // 使用快捷键 tab 取消显示完整单词
  useHotkeys(
    'ctrl+j',
    () => {
      if (state.isTyping) {
        wordPronunciationIconRef.current?.play()
      }
    },
    [state.isTyping],
    { enableOnFormTags: true, preventDefault: true },
  ) // 使用快捷键 ctrl+j 播放单词发音

  useEffect(() => {
    if (wordState.inputWord.length === 0 && state.isTyping) {
      wordPronunciationIconRef.current?.play && wordPronunciationIconRef.current?.play()
    }
  }, [state.isTyping, wordState.inputWord.length, wordPronunciationIconRef.current?.play])

  const getLetterVisible = useCallback(
    // 计算字母是否可见的回调函数
    (index: number) => {
      if (wordState.letterStates[index] === 'correct' || (isShowAnswerOnHover && isHoveringWord)) return true

      if (wordDictationConfig.isOpen) {
        if (wordDictationConfig.type === 'hideAll') return false

        const letter = wordState.displayWord[index]
        if (wordDictationConfig.type === 'hideVowel') {
          return vowelLetters.includes(letter.toUpperCase()) ? false : true
        }
        if (wordDictationConfig.type === 'hideConsonant') {
          return vowelLetters.includes(letter.toUpperCase()) ? true : false
        }
        if (wordDictationConfig.type === 'randomHide') {
          return wordState.randomLetterVisible[index]
        }
      }
      return true
    },
    [
      isHoveringWord,
      isShowAnswerOnHover,
      wordDictationConfig.isOpen,
      wordDictationConfig.type,
      wordState.displayWord,
      wordState.letterStates,
      wordState.randomLetterVisible,
    ],
  ) // 计算字母是否可见的回调函数

  useEffect(() => {
    const inputLength = wordState.inputWord.length // 获取用户输入的长度
    /**
     * TODO: 当用户输入错误时，会报错
     * Cannot update a component (`App`) while rendering a different component (`WordComponent`). To locate the bad setState() call inside `WordComponent`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
     * 目前不影响生产环境，猜测是因为开发环境下 react 会两次调用 useEffect 从而展示了这个 warning
     * 但这终究是一个 bug，需要修复
     */
    if (wordState.hasWrong || inputLength === 0 || wordState.displayWord.length === 0) {
      return
    }

    const inputChar = wordState.inputWord[inputLength - 1] // 获取用户输入的最后一个字符
    const correctChar = wordState.displayWord[inputLength - 1] // 获取正确单词的对应字符
    let isEqual = false
    if (inputChar != undefined && correctChar != undefined) {
      isEqual = isIgnoreCase ? inputChar.toLowerCase() === correctChar.toLowerCase() : inputChar === correctChar //isEqual 判断用户输入的字符是否正确
    }

    if (isEqual) {
      // 输入正确时
      setWordState((state) => {
        // 使用 immer 的方式更新状态
        state.letterTimeArray.push(Date.now()) // 记录字母输入时间
        state.correctCount += 1 // 正确输入次数加 1
      })

      if (inputLength >= wordState.displayWord.length) {
        // 完成输入时
        // 完成输入时
        setWordState((state) => {
          state.letterStates[inputLength - 1] = 'correct'
          state.isFinished = true
          state.endTime = getUtcStringForMixpanel()
        }) // 设置最后一个字母状态为正确，标记单词完成，记录结束时间
        playHintSound() // 播放提示音
      } else {
        setWordState((state) => {
          state.letterStates[inputLength - 1] = 'correct'
        })
        playKeySound() // 播放按键音
      }

      dispatch({ type: TypingStateActionType.REPORT_CORRECT_WORD }) // 向全局状态报告正确输入的字数
    } else {
      // 出错时
      playBeepSound()
      setWordState((state) => {
        state.letterStates[inputLength - 1] = 'wrong' // 设置当前字母状态为错误
        state.hasWrong = true // 标记单词状态为错误
        state.hasMadeInputWrong = true // 标记已经出现过输入错误
        state.wrongCount += 1 // 错误输入次数加 1
        state.letterTimeArray = [] // 重置字母输入时间数组

        if (state.letterMistake[inputLength - 1]) {
          // 记录错误的字母和位置
          state.letterMistake[inputLength - 1].push(inputChar) //  记录错误的字母和位置
        } else {
          state.letterMistake[inputLength - 1] = [inputChar] //  记录错误的字母和位置
        }

        const currentState = JSON.parse(JSON.stringify(state)) // 深拷贝当前状态以避免闭包问题
        dispatch({ type: TypingStateActionType.REPORT_WRONG_WORD, payload: { letterMistake: currentState.letterMistake } }) // 向全局状态报告错误输入的字数和错误详情
      })

      if (currentChapter === 0 && state.chapterData.index === 0 && wordState.wrongCount >= 3) {
        // 如果是第一章节的第一个单词且错误次数超过3次，则显示提示警告
        setShowTipAlert(true) // 显示提示警告
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [wordState.inputWord]) // 监听输入的变化，更新单词状态

  useEffect(() => {
    if (wordState.hasWrong) {
      const timer = setTimeout(() => {
        setWordState((state) => {
          state.inputWord = ''
          state.letterStates = new Array(state.letterStates.length).fill('normal')
          state.hasWrong = false
        })
      }, 300) // 300ms 后重置输入

      return () => {
        clearTimeout(timer) // 清除定时器
      }
    } // 300ms 后重置输入
  }, [wordState.hasWrong, setWordState]) // 当单词状态为错误时，300ms 后重置输入

  useEffect(() => {
    if (wordState.isFinished) {
      // 当单词输入完成时
      dispatch({ type: TypingStateActionType.SET_IS_SAVING_RECORD, payload: true }) // 设置正在保存记录状态

      // wordLogUploader({
      //   headword: word.name,
      //   timeStart: wordState.startTime,
      //   timeEnd: wordState.endTime,
      //   countInput: wordState.correctCount + wordState.wrongCount,
      //   countCorrect: wordState.correctCount,
      //   countTypo: wordState.wrongCount,
      // })// 上传单词日志
      saveWordRecord({
        word: word.name,
        wrongCount: wordState.wrongCount,
        letterTimeArray: wordState.letterTimeArray,
        letterMistake: wordState.letterMistake,
      }) // 保存单词记录

      onFinish() // 调用完成回调
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [wordState.isFinished]) // 当单词输入完成时，保存单词记录并调用 onFinish 回调

  useEffect(() => {
    if (wordState.wrongCount >= 4) {
      // 如果错误次数超过4次，则自动跳过该单词
      dispatch({ type: TypingStateActionType.SET_IS_SKIP, payload: true })
    }
  }, [wordState.wrongCount, dispatch]) // 监听错误次数的变化，超过4次则跳过单词
  console.log('1231313113', style.wrong)
  return (
    <>
      <InputHandler updateInput={updateInput} />
      <div
        lang={currentLanguageCategory !== 'code' ? currentLanguageCategory : 'en'} // 设置语言属性，代码类语言统一使用英文
        className="flex flex-col items-center justify-center pb-1 pt-4" // 设置容器样式
      >
        {['romaji', 'hapin'].includes(currentLanguage) && word.notation && <Notation notation={word.notation} />}
        <div
          className={`tooltip-info relative w-fit bg-transparent p-0 leading-normal shadow-none dark:bg-transparent ${
            // 如果开启单词听写功能则显示提示
            wordDictationConfig.isOpen ? 'tooltip' : '' // 如果开启单词听写功能则显示提示
          }`}
          data-tip="按 Tab 快捷键显示完整单词"
        >
          <div
            onMouseEnter={() => handleHoverWord(true)}
            onMouseLeave={() => handleHoverWord(false)}
            className={`flex items-center ${isTextSelectable && 'select-all'} justify-center ${wordState.hasWrong ? style.wrong : ''}`} // 如果允许选中文字则添加 select-all 类名，如果单词状态为错误则添加错误样式
          >
            {wordState.displayWord.split('').map((t, index) => {
              return <Letter key={`${index}-${t}`} letter={t} visible={getLetterVisible(index)} state={wordState.letterStates[index]} />
            })}
          </div>
          {pronunciationIsOpen && (
            <div className="absolute -right-12 top-1/2 h-9 w-9 -translate-y-1/2 transform ">
              <Tooltip content={`快捷键${CTRL} + J`}>
                <WordPronunciationIcon word={word} lang={currentLanguage} ref={wordPronunciationIconRef} className="h-full w-full" />
              </Tooltip>
            </div>
          )}
        </div>
      </div>
      <TipAlert className="fixed bottom-10 right-3" show={showTipAlert} setShow={setShowTipAlert} />
    </>
  )
}
